package cn.hl.hm.util.wxjs;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.ConnectException;
import java.security.KeyManagementException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;

import javax.net.ssl.HttpsURLConnection;

import org.apache.commons.httpclient.ProtocolException;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import org.apache.log4j.Logger;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;

import cn.hl.hm.constants.ModelConfig;
import net.sf.json.JSONObject;



public class CommonUtil {
	 private static Logger log = Logger.getLogger(CommonUtil.class);
	 
	 public static JSONObject httpsRequestToJsonObject(String requestUrl, String requestMethod, String outputStr) {
	  JSONObject jsonObject = null;
	  try {
	  StringBuffer buffer = httpsRequest(requestUrl, requestMethod, outputStr);
	  jsonObject = JSONObject.fromObject(buffer.toString());
	  } catch (ConnectException ce) {
	  log.info("连接超时："+ce.getMessage());
	  } catch (Exception e) {
	  log.info("https请求异常："+e.getMessage());
	  }
	  return jsonObject;
	 }
	  
	 private static StringBuffer httpsRequest(String requestUrl, String requestMethod, String output)
	  throws NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException, MalformedURLException,
	  IOException, ProtocolException, UnsupportedEncodingException {
	  URL url = new URL(requestUrl);
	  HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
	  connection.setDoOutput(true);
	  connection.setDoInput(true);
	  connection.setUseCaches(false);
	  connection.setRequestMethod(requestMethod);
	  if (null != output) {
	  OutputStream outputStream = connection.getOutputStream();
	  outputStream.write(output.getBytes("UTF-8"));
	  outputStream.close();
	  }
	  // 从输入流读取返回内容
	  InputStream inputStream = connection.getInputStream();
	  InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
	  BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
	  String str = null;
	  StringBuffer buffer = new StringBuffer();
	  while ((str = bufferedReader.readLine()) != null) {
	  buffer.append(str);
	  }
	  bufferedReader.close();
	  inputStreamReader.close();
	  inputStream.close();
	  inputStream = null;
	  connection.disconnect();
	  return buffer;
	 }
	 
	 //随机字符串：我用的是UUID去中划线
	 public static String create_nonce_str() {
		 return UUID.randomUUID().toString().replace("-","");
	 }
	 
	 
	 /**
	  * 创建统一下单的xml的java对象
	  * @param bizOrder 系统中的业务单号
	  * @param ip 用户的ip地址
	  * @param openId 用户的openId
	  * @return
	  */
	  public static PayInfo createPayInfo(BizOrder bizOrder,String ip,String openId) {

	   PayInfo payInfo = new PayInfo();
	   payInfo.setAppid(ModelConfig.appid);
	   payInfo.setDevice_info(bizOrder.getSeriNum()+"");
	   payInfo.setMch_id(ModelConfig.mch_id);
	   payInfo.setNonce_str(CommonUtil.create_nonce_str().replace("-", ""));
	   payInfo.setBody("华凌-配载费");
	   payInfo.setAttach(bizOrder.getId());
       payInfo.setOut_trade_no(bizOrder.getOrderCode());//本来就是这样
	   //payInfo.setOut_trade_no(bizOrder.getOrderCode().concat("A").concat(DateFormatUtils.format(new Date(), "MMddHHmmss")));
	   payInfo.setTotal_fee((int)bizOrder.getFeeAmount());
	   payInfo.setSpbill_create_ip(ip);
	   
	   if(ModelConfig.status.equals("0")){
		   payInfo.setNotify_url(ModelConfig.wx_js_notify_url_test );
	   }else {
		   payInfo.setNotify_url(ModelConfig.wx_js_notify_url_online );
	   }
	   payInfo.setTrade_type("NATIVE");
	   payInfo.setOpenid(openId);
	   
	   return payInfo;
	  }

	  
	  /**
	   * 获取签名
	   * @param payInfo
	   * @return
	   * @throws Exception
	   */
	   public static String getSign(PayInfo payInfo) throws Exception {
	    String signTemp = "appid="+payInfo.getAppid()
	     +"&attach="+payInfo.getAttach()
	     +"&body="+payInfo.getBody()
	     +"&device_info="+payInfo.getDevice_info()
	     +"&mch_id="+payInfo.getMch_id()
	     +"&nonce_str="+payInfo.getNonce_str()
	     +"&notify_url="+payInfo.getNotify_url()
	 //    +"&openid="+payInfo.getOpenid()
	     +"&out_trade_no="+payInfo.getOut_trade_no()
	     +"&spbill_create_ip="+payInfo.getSpbill_create_ip()
	     +"&total_fee="+payInfo.getTotal_fee()
	     +"&trade_type="+payInfo.getTrade_type()
	     +"&key="+ModelConfig.key; //这个key注意
	    System.out.println("signTemp:   "+signTemp);
	   MessageDigest md = MessageDigest.getInstance("MD5");
	   md.reset();
	   md.update(signTemp.getBytes("UTF-8"));
	   
//	   String sign = Hex.encodeHexStr(signTemp.getBytes("UTF-8")).toUpperCase();

	   String sign = CommonUtil.byteToStr(md.digest()).toUpperCase();
	   System.out.println("sign: "+ sign);
	   
	   return sign;
	   }

		  /**
		   * 获取签名
		   * @param payOrderInfo
		   * @return
		   * @throws Exception
		   */
		   public static String getSign1(String appId,String timeStamp,String nonceStr,String package1,String signType ) throws Exception {
			
			StringBuffer signTemp = new StringBuffer();
		    SortedMap<String,String> map = null ;  
            map = new TreeMap<String,String>() ;   //通过子类实例化接口对象
            map.put("appId",appId) ;
            map.put("timeStamp",timeStamp) ;
            map.put("nonceStr",nonceStr) ;
            map.put("package",package1) ;
            map.put("signType",signType) ;
		    
		    Set es = map.entrySet();//所有参与传参的参数按照accsii排序(升序)
		    
	        Iterator it = es.iterator();  
	        while(it.hasNext()) {  
	            Map.Entry entry = (Map.Entry)it.next();  
	            String k = (String)entry.getKey();  
	            Object v = entry.getValue();  
	            if(null != v && !"".equals(v)   
	                    && !"sign".equals(k) && !"key".equals(k)) {  
	            	signTemp.append(k + "=" + v + "&");  
	            }  
	        }  
	        signTemp.append("key=" + ModelConfig.key);
		    
//		   MessageDigest md = MessageDigest.getInstance("MD5");
//		   md.reset();
//		   md.update(signTemp.getBytes("UTF-8"));
		   
//		   String sign = Hex.encodeHexStr(signTemp.getBytes("UTF-8")).toUpperCase();
//		   String sign = CommonUtil.byteToStr(md.digest()).toUpperCase();
	        
	       String sign = CommonUtil.MD5Encode(signTemp.toString(), "UTF-8").toUpperCase();
	       
		   System.out.println("signTemp1: "+ signTemp.toString());
		   System.out.println("sign1: "+ sign);
		   return sign;
		   }
	   
	   
	   /**
	   * 将字节数组转换为十六进制字符串
	   * 
	   * @param byteArray
	   * @return
	   */
	   public static String byteToStr(byte[] byteArray) {
	    String strDigest = "";
	    for (int i = 0; i < byteArray.length; i++) {
	    strDigest += byteToHexStr(byteArray[i]);
	    }
	    return strDigest;
	   }
	   /**
	   * 将字节转换为十六进制字符串
	   * 
	   * @param btyes
	   * @return
	   */
	   public static String byteToHexStr(byte src) {
		    char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
//		    char[] tempArr = new char[];
//		    tempArr[] = Digit[(bytes >>> ) & XF];
//		    tempArr[] = Digit[bytes & XF];
//		    String s = new String(tempArr);
		    
		    StringBuilder stringBuilder = new StringBuilder("");  


		        int v = src & 0xFF;  
		        String hv = Integer.toHexString(v);  
		        if (hv.length() < 2) {  
		            stringBuilder.append(0);  
		        }  
		        stringBuilder.append(hv);  

		    return stringBuilder.toString();
	   }
	   
	   
	   private static String byteArrayToHexString(byte b[]) {  
	        StringBuffer resultSb = new StringBuffer();  
	        for (int i = 0; i < b.length; i++)  
	            resultSb.append(byteToHexString(b[i]));  
	  
	        return resultSb.toString();  
	    }  
	  
	    private static String byteToHexString(byte b) {  
	        int n = b;  
	        if (n < 0)  
	            n += 256;  
	        int d1 = n / 16;  
	        int d2 = n % 16;  
	        return hexDigits[d1] + hexDigits[d2];  
	    }  
	  
	    public static String MD5Encode(String origin, String charsetname) {  
	        String resultString = null;  
	        try {  
	            resultString = new String(origin);  
	            MessageDigest md = MessageDigest.getInstance("MD5");  
	            if (charsetname == null || "".equals(charsetname))  
	                resultString = byteArrayToHexString(md.digest(resultString  
	                        .getBytes()));  
	            else  
	                resultString = byteArrayToHexString(md.digest(resultString  
	                        .getBytes(charsetname)));  
	        } catch (Exception exception) {  
	        }  
	        return resultString;  
	    }  
	  
	    private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",  
	        "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; 
	   
//	   /**
//	   * 获取ip地址
//	   * @param request
//	   * @return
//	   */
//	   public static String getIpAddr(HttpServletRequest request) { 
//	    InetAddress addr = null; 
//	    try { 
//	    addr = InetAddress.getLocalHost(); 
//	    } catch (UnknownHostException e) { 
//	    return request.getRemoteAddr(); 
//	    } 
//	    byte[] ipAddr = addr.getAddress(); 
//	    String ipAddrStr = ""; 
//	    for (int i = ; i < ipAddr.length; i++) { 
//	    if (i > ) { 
//	     ipAddrStr += "."; 
//	    } 
//	    ipAddrStr += ipAddr[i] & xFF; 
//	    } 
//	    return ipAddrStr; 
//	   }
	   
	   /**
	   * 扩展xstream使其支持CDATA
	   */
	   private static XStream xstream = new XStream(new XppDriver() {
	    public HierarchicalStreamWriter createWriter(Writer out) {
	    return new PrettyPrintWriter(out) {
	     //增加CDATA标记
	     boolean cdata = true;
	     @SuppressWarnings("rawtypes")
	     public void startNode(String name, Class clazz) {
	     super.startNode(name, clazz);
	     }
	     protected void writeText(QuickWriter writer, String text) {
	     if (cdata) {
	      writer.write("<![CDATA[");
	      writer.write(text);
	      writer.write("]]>");
	     } else {
	      writer.write(text);
	     }
	     }
	    };
	    }
	   });
	   
	   public static String payInfoToXML(PayInfo pi) {
	    xstream.alias("xml", pi.getClass());
	    return xstream.toXML(pi);
	   }
	   
	   
	   @SuppressWarnings("unchecked")
	   public static Map<String, String> parseXml(String xml) throws Exception {
		   Map<String, String> map = new HashMap<String, String>();
		   Document document = DocumentHelper.parseText(xml);
		   Element root = document.getRootElement();
		   List<Element> elementList = root.elements();
		   for (Element e : elementList)
		   map.put(e.getName(), e.getText());
		   return map;
	   }
	   
	   public static Map<String, String> httpsRequestToXML(String requestUrl, String requestMethod, String outputStr) {
		   Map<String, String> result = new HashMap<>();
		   try {
			   StringBuffer buffer = httpsRequest(requestUrl, requestMethod, outputStr);
			   result = CommonUtil.parseXml(buffer.toString());
		   } catch (ConnectException ce) {
			   log.info("连接超时："+ce.getMessage());
		   } catch (Exception e) {
			   log.info("https请求异常："+e.getMessage());
		   }
		   return result;
		   }
	 
	 
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		//1. openId
		String codestr ="031sfbJn0D56Be1mWAJn0nOhJn0sfbJ2";
		  String oauth_url = ModelConfig.oauth_url.replace("APPID", ModelConfig.appid).replace("SECRET", ModelConfig.appsecret).replace("CODE", String.valueOf(codestr));
		  	log.info("oauth_url:"+oauth_url);
		  JSONObject jsonObject = CommonUtil.httpsRequestToJsonObject(oauth_url, "POST", null);
		  	log.info("jsonObject:"+jsonObject);
		  Object errorCode = jsonObject.get("errcode");
		  if(errorCode != null) {
			  log.info("code不合法");
		  }else{
			  String openId = jsonObject.getString("openid");
			  log.info("openId:"+openId);
			  
			  
			  //2. sign
			  BizOrder bo = new BizOrder();
			  bo.setId("1001");
			  bo.setFeeAmount(1);
			  bo.setOrderCode("A0000001");

			  PayInfo pi = CommonUtil.createPayInfo(bo,"192.168.0.1",openId);
			  String sign;
			try {
				sign = CommonUtil.getSign(pi);
				pi.setSign(sign);
				
				//3 调用统一下单接口
				log.info(CommonUtil.payInfoToXML(pi).replace("__", "_"));
				Map<String, String> map = CommonUtil.httpsRequestToXML("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", CommonUtil.payInfoToXML(pi).replace("__", "_").replace("<![CDATA[", "").replace("]]>", ""));
			 	log.info(map.toString());
			 	
			 	String return_code = map.get("return_code");
			 	 if(return_code.equals("SUCCESS")){
			 		 String return_msg = map.get("return_msg");
				 	 if(!return_msg.equals("OK")) {
				 		log.info("统一下单错误！");
				 	 }else{
				 		log.info("统一下单OK！");
				 	 }
			 	 }else{
			 		log.info("统一下单错误！");
			 	 }
			 	 String prepay_Id = map.get("prepay_id");
			 	 log.info("prepay_id:" + prepay_Id);
			 	
			 	//4 调起支付接口
				 
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			  
			  
			  
		  }
		  

		  

	}
	
}
